Header file strong_typedef.hpp

#define TYPE_SAFE_DETAIL_MAKE_OP_OTHER_STRONGTYPEDEF

#define TYPE_SAFE_DETAIL_MAKE_OP_MIXED

namespace type_safe
{
    template <class Tag, typename T>
    class strong_typedef;
    
    template <class StrongTypedef>
    using underlying_type = 'hidden';
    
    template <class Tag, typename T>
    constexpr T& get(strong_typedef<Tag, T>& type) noexcept;
    template <class Tag, typename T>
    constexpr const T& get(const strong_typedef<Tag, T>& type) noexcept;
    template <class Tag, typename T>
    constexpr T&& get(strong_typedef<Tag, T>&& type) noexcept;
    template <class Tag, typename T>
    constexpr const T&& get(const strong_typedef<Tag, T>&& type) noexcept;
    
    namespace strong_typedef_op
    {
        template <class StrongTypedef>
        struct equality_comparison
        {
        };
        
        template <class StrongTypedef, typename Other>
        struct mixed_equality_comparison
        {
        };
        
        template <class StrongTypedef>
        struct relational_comparison
        {
        };
        
        template <class StrongTypedef, typename Other>
        struct mixed_relational_comparison
        {
        };
        
        template <class StrongTypedef>
        struct addition
        {
        };
        
        template <class StrongTypedef>
        struct explicit_bool
        {
        };
        
        template <class StrongTypedef>
        struct increment
        {
        };
        
        template <class StrongTypedef>
        struct decrement
        {
        };
        
        template <class StrongTypedef>
        struct unary_plus
        {
        };
        
        template <class StrongTypedef>
        struct unary_minus
        {
        };
        
        template <class StrongTypedef>
        struct integer_arithmetic
        : unary_plus<StrongTypedef>,
          unary_minus<StrongTypedef>,
          addition<StrongTypedef>,
          'hidden',
          'hidden',
          'hidden',
          'hidden',
          increment<StrongTypedef>,
          decrement<StrongTypedef>
        {
        };
        
        template <class StrongTypedef>
        struct floating_point_arithmetic
        : unary_plus<StrongTypedef>,
          unary_minus<StrongTypedef>,
          addition<StrongTypedef>,
          'hidden',
          'hidden',
          'hidden'
        {
        };
        
        template <class StrongTypedef>
        struct complement
        {
        };
        
        template <class StrongTypedef>
        struct bitwise_or
        {
        };
        
        template <class StrongTypedef>
        struct bitmask
        : complement<StrongTypedef>,
          bitwise_or<StrongTypedef>,
          'hidden',
          'hidden'
        {
        };
        
        template <class StrongTypedef, typename IntT>
        struct bitshift
        {
        };
        
        template <class StrongTypedef, typename Result, typename ResultPtr = Result*, typename ResultConstPtr = const Result*>
        struct dereference
        {
        };
        
        template <class StrongTypedef, typename Result, typename Index = std::size_t>
        struct array_subscript
        {
        };
        
        template <class StrongTypedef, class Category, typename T, typename Distance = std::ptrdiff_t>
        struct iterator
        : dereference<StrongTypedef, T, T *, const T *>,
          increment<StrongTypedef>
        {
            using iterator_category = Category;
            
            using value_type = typename std::remove_cv<T>::type;
            
            using difference_type = Distance;
            
            using pointer = T*;
            
            using reference = T&;
        };
        
        template <class StrongTypedef, typename T, typename Distance = std::ptrdiff_t>
        struct input_iterator
        : iterator<StrongTypedef, std::input_iterator_tag, T, Distance>,
          equality_comparison<StrongTypedef>
        {
        };
        
        template <class StrongTypedef, typename T, typename Distance = std::ptrdiff_t>
        struct output_iterator
        : iterator<StrongTypedef, std::output_iterator_tag, T, Distance>
        {
        };
        
        template <class StrongTypedef, typename T, typename Distance = std::ptrdiff_t>
        struct forward_iterator
        : input_iterator<StrongTypedef, T, Distance>
        {
            using iterator_category = std::forward_iterator_tag;
        };
        
        template <class StrongTypedef, typename T, typename Distance = std::ptrdiff_t>
        struct bidirectional_iterator
        : forward_iterator<StrongTypedef, T, Distance>,
          decrement<StrongTypedef>
        {
            using iterator_category = std::bidirectional_iterator_tag;
        };
        
        template <class StrongTypedef, typename T, typename Distance = std::ptrdiff_t>
        struct random_access_iterator
        : bidirectional_iterator<StrongTypedef, T, Distance>,
          array_subscript<StrongTypedef, T, Distance>,
          relational_comparison<StrongTypedef>
        {
            using iterator_category = std::random_access_iterator_tag;
        };
        
        template <class StrongTypedef>
        struct input_operator
        {
        };
        
        template <class StrongTypedef>
        struct output_operator
        {
        };
    }
    
    template <class StrongTypedef>
    struct hashable;
}

Class template type_safe::strong_typedef

template <class Tag, typename T>
class strong_typedef
{
public:
    constexpr strong_typedef();
    
    constexpr strong_typedef(const T& value);
    constexpr strong_typedef(T&& value) noexcept('hidden');
    
    constexpr operator T&() & noexcept;
    constexpr operator const T&() const & noexcept;
    constexpr operator T&&() && noexcept;
    constexpr operator const T&&() const && noexcept;
    
    friend void swap(strong_typedef& a, strong_typedef& b) noexcept;
};

A strong typedef emulation.

Unlike regular typedefs, this does create a new type and only allows explicit conversion from the underlying one. The Tag is used to differentiate between different strong typedefs to the same type. It is designed to be used as a base class and does not provide any operations by itself. Use the types in the strong_typedef_op namespace to generate operations and/or your own member functions.

Example:

struct my_handle
: strong_typedef<my_handle, void*>,
  strong_typedef_op::equality_comparison<my_handle>
{
    using strong_typedef::strong_typedef;
};

struct my_int
: strong_typedef<my_int, int>,
  strong_typedef_op::integer_arithmetic<my_int>,
  strong_typedef_op::equality_comparison<my_int>,
  strong_typedef_op::relational_comparison<my_int>
{
    using strong_typedef::strong_typedef;
};

Default constructor type_safe::strong_typedef::strong_typedef

constexpr strong_typedef();

Effects: Value initializes the underlying value.

Constructor type_safe::strong_typedef::strong_typedef

(1)  constexpr strong_typedef(const T& value);

(2)  constexpr strong_typedef(T&& value) noexcept('hidden');

Effects: Copy (1)/moves (2) the underlying value.

Conversion operator type_safe::strong_typedef::operator T&

(1)  constexpr operator T&() & noexcept;

(2)  constexpr operator const T&() const & noexcept;

(3)  constexpr operator T&&() && noexcept;

(4)  constexpr operator const T&&() const && noexcept;

Returns: A reference to the stored underlying value.


Alias template type_safe::underlying_type

template <class StrongTypedef>
using underlying_type = 'hidden';

The underlying type of the ts::strong_typedef.

Function template type_safe::get

(1)  template <class Tag, typename T>
     constexpr T& get(strong_typedef<Tag, T>& type) noexcept;

(2)  template <class Tag, typename T>
     constexpr const T& get(const strong_typedef<Tag, T>& type) noexcept;

(3)  template <class Tag, typename T>
     constexpr T&& get(strong_typedef<Tag, T>&& type) noexcept;

(4)  template <class Tag, typename T>
     constexpr const T&& get(const strong_typedef<Tag, T>&& type) noexcept;

Accesses the underlying value.

Returns: A reference to the underlying value.

Namespace type_safe::strong_typedef_op

namespace strong_typedef_op
{
    template <class StrongTypedef>
    struct equality_comparison
    {
    };
    
    template <class StrongTypedef, typename Other>
    struct mixed_equality_comparison
    {
    };
    
    template <class StrongTypedef>
    struct relational_comparison
    {
    };
    
    template <class StrongTypedef, typename Other>
    struct mixed_relational_comparison
    {
    };
    
    template <class StrongTypedef>
    struct addition
    {
    };
    
    template <class StrongTypedef>
    struct explicit_bool
    {
    };
    
    template <class StrongTypedef>
    struct increment
    {
    };
    
    template <class StrongTypedef>
    struct decrement
    {
    };
    
    template <class StrongTypedef>
    struct unary_plus
    {
    };
    
    template <class StrongTypedef>
    struct unary_minus
    {
    };
    
    template <class StrongTypedef>
    struct integer_arithmetic
    : unary_plus<StrongTypedef>,
      unary_minus<StrongTypedef>,
      addition<StrongTypedef>,
      'hidden',
      'hidden',
      'hidden',
      'hidden',
      increment<StrongTypedef>,
      decrement<StrongTypedef>
    {
    };
    
    template <class StrongTypedef>
    struct floating_point_arithmetic
    : unary_plus<StrongTypedef>,
      unary_minus<StrongTypedef>,
      addition<StrongTypedef>,
      'hidden',
      'hidden',
      'hidden'
    {
    };
    
    template <class StrongTypedef>
    struct complement
    {
    };
    
    template <class StrongTypedef>
    struct bitwise_or
    {
    };
    
    template <class StrongTypedef>
    struct bitmask
    : complement<StrongTypedef>,
      bitwise_or<StrongTypedef>,
      'hidden',
      'hidden'
    {
    };
    
    template <class StrongTypedef, typename IntT>
    struct bitshift
    {
    };
    
    template <class StrongTypedef, typename Result, typename ResultPtr = Result*, typename ResultConstPtr = const Result*>
    struct dereference
    {
    };
    
    template <class StrongTypedef, typename Result, typename Index = std::size_t>
    struct array_subscript
    {
    };
    
    template <class StrongTypedef, class Category, typename T, typename Distance = std::ptrdiff_t>
    struct iterator
    : dereference<StrongTypedef, T, T *, const T *>,
      increment<StrongTypedef>
    {
        using iterator_category = Category;
        
        using value_type = typename std::remove_cv<T>::type;
        
        using difference_type = Distance;
        
        using pointer = T*;
        
        using reference = T&;
    };
    
    template <class StrongTypedef, typename T, typename Distance = std::ptrdiff_t>
    struct input_iterator
    : iterator<StrongTypedef, std::input_iterator_tag, T, Distance>,
      equality_comparison<StrongTypedef>
    {
    };
    
    template <class StrongTypedef, typename T, typename Distance = std::ptrdiff_t>
    struct output_iterator
    : iterator<StrongTypedef, std::output_iterator_tag, T, Distance>
    {
    };
    
    template <class StrongTypedef, typename T, typename Distance = std::ptrdiff_t>
    struct forward_iterator
    : input_iterator<StrongTypedef, T, Distance>
    {
        using iterator_category = std::forward_iterator_tag;
    };
    
    template <class StrongTypedef, typename T, typename Distance = std::ptrdiff_t>
    struct bidirectional_iterator
    : forward_iterator<StrongTypedef, T, Distance>,
      decrement<StrongTypedef>
    {
        using iterator_category = std::bidirectional_iterator_tag;
    };
    
    template <class StrongTypedef, typename T, typename Distance = std::ptrdiff_t>
    struct random_access_iterator
    : bidirectional_iterator<StrongTypedef, T, Distance>,
      array_subscript<StrongTypedef, T, Distance>,
      relational_comparison<StrongTypedef>
    {
        using iterator_category = std::random_access_iterator_tag;
    };
    
    template <class StrongTypedef>
    struct input_operator
    {
    };
    
    template <class StrongTypedef>
    struct output_operator
    {
    };
}

Some operations for ts::strong_typedef.

They all generate operators forwarding to the underlying type. Inherit from them in the typedef definition.

Class template type_safe::hashable

template <class StrongTypedef>
struct hashable
: std::hash<type_safe::underlying_type<StrongTypedef> >
{
    using underlying_type = type_safe::underlying_type<StrongTypedef>;
    
    using underlying_hash = std::hash<underlying_type>;
    
    std::size_t operator()(const StrongTypedef& lhs) const noexcept('hidden');
};

Inherit from it in the std::hash<StrongTypedef> specialization to make it hashable like the underlying type. See example/strong_typedef.cpp.